/**
 * 消息相关组件集合
 * 包含用户消息、AI消息、消息操作等组件
 */
import React, { useState, useRef, useMemo, useCallback, useEffect, lazy, Suspense } from 'react';
import {
    Box,
    Typography,
    IconButton,
    Paper,
    Tooltip,
    useTheme,
    alpha,
    styled,
    Button,
    Alert,
    CircularProgress
} from '@mui/material';
import {
    ContentCopy as CopyIcon,
    Check as CheckIcon,
    PushPin as PushPinIcon,
    PushPinOutlined as PushPinOutlinedIcon,
    SmartToy as SmartToyIcon
} from '@mui/icons-material';
import { Message } from '../../../types/chat.ts';
import MarkdownRenderer from './MarkdownRenderer.tsx';
import { extractPolishedText } from '../../../utils/ai/responseUtils.ts';
import { useNovel } from '../../../context/NovelContext.tsx';
import { calculateTextDiff } from '../../../utils/fileSystem/diffUtils.ts';
import { requestTextReplace } from '../../../services/editorService.ts';
import { showToast, showErrorToast } from '../../../utils/ui/toast.ts';
import { ReplaceOperation } from '../../../types/ai.ts';

// 懒加载差异展示组件，避免循环引用
const TextDiffDisplay = lazy(() => import('./TextDiffDisplay.tsx'));

// 用户消息样式 - 更简洁，类似Cursor设计
export const UserMessage = styled(Box)(({ theme }) => ({
    padding: theme.spacing(2, 3),
    backgroundColor: alpha(theme.palette.primary.main, 0.04),
    position: 'relative',
    margin: theme.spacing(0.5, 0),
    borderRadius: theme.shape.borderRadius,
}));

// AI消息样式
export const AIMessage = styled(Box)(({ theme }) => ({
    padding: theme.spacing(2, 3),
    backgroundColor: theme.palette.background.paper,
    position: 'relative',
    margin: theme.spacing(0.5, 0),
    borderRadius: theme.shape.borderRadius,
    boxShadow: `0 1px 2px ${alpha(theme.palette.common.black, 0.05)}`,
}));

// 流式消息的样式
export const StreamingAIMessage = styled(AIMessage)(({ theme }) => ({
    // 移除脉冲点动画，只保留淡入动画
    '&.fade-in': {
        animation: 'fadeIn 0.3s ease-in-out',
    },
    '@keyframes fadeIn': {
        '0%': {
            opacity: 0.7,
            transform: 'translateY(5px)',
        },
        '100%': {
            opacity: 1,
            transform: 'translateY(0)',
        },
    },
}));

// 消息组样式
export const MessagesContainer = styled(Box)(({ theme }) => ({
    display: 'flex',
    flexDirection: 'column',
}));

// 消息操作按钮样式
export const MessageActionButton = styled(IconButton)(({ theme }) => ({
    padding: 2,
    fontSize: '0.75rem',
    color: alpha(theme.palette.text.primary, 0.6),
    '&:hover': {
        color: theme.palette.primary.main,
        backgroundColor: alpha(theme.palette.primary.main, 0.08),
    },
}));

// 消息操作区域
export const MessageActions = styled(Box)(({ theme }) => ({
    position: 'absolute',
    top: '8px',
    right: '8px',
    display: 'flex',
    gap: '4px',
    opacity: 0,
    transition: 'opacity 0.2s ease-in-out',
    '&:hover': {
        opacity: 1,
    },
}));

// 高亮当前悬停的消息的操作按钮
export const MessageContainer = styled(Box)(({ theme }) => ({
    position: 'relative',
    '&:hover': {
        '& .MuiBox-root > .message-actions': {
            opacity: 1,
        },
    },
}));

// 添加带动画效果的打字指示器组件
export const TypingDots = styled(Box)(({ theme }) => ({
    display: 'inline-flex',
    alignItems: 'center',
    justifyContent: 'center',
    gap: '5px',
    padding: theme.spacing(1.5, 2),
    borderRadius: theme.shape.borderRadius,
    backgroundColor: alpha(theme.palette.background.paper, 0.7),
    boxShadow: `0 2px 6px ${alpha(theme.palette.common.black, 0.06)}`,
    backdropFilter: 'blur(8px)',
    width: 'fit-content',
    position: 'relative',
    '&::before': {
        content: '""',
        position: 'absolute',
        left: 0,
        top: '50%',
        transform: 'translateY(-50%)',
        width: '3px',
        height: '60%',
        backgroundColor: theme.palette.primary.main,
        borderRadius: '0 2px 2px 0',
    },
    '& .dot': {
        width: '8px',
        height: '8px',
        borderRadius: '50%',
        backgroundColor: theme.palette.primary.main,
        opacity: 0.8,
        animation: 'bounce 1.4s infinite ease-in-out both',
        filter: `drop-shadow(0 1px 2px ${alpha(theme.palette.primary.main, 0.3)})`,
    },
    '& .dot:nth-child(1)': {
        animationDelay: '-0.32s',
    },
    '& .dot:nth-child(2)': {
        animationDelay: '-0.16s',
    },
    '@keyframes bounce': {
        '0%, 80%, 100%': {
            transform: 'scale(0)',
        },
        '40%': {
            transform: 'scale(1)',
        },
    },
}));

// 用于AI头像的样式
export const AIIcon = styled(Box)(({ theme }) => ({
    display: 'inline-flex',
    alignItems: 'center',
    justifyContent: 'center',
    backgroundColor: theme.palette.primary.main,
    color: '#fff',
    width: 24,
    height: 24,
    borderRadius: '50%',
    marginRight: theme.spacing(1),
}));

interface SingleMessageProps {
    message: Message;
    isHovered: boolean;
    isPinned: boolean;
    onCopy?: () => void;
    onTogglePin?: () => void;
}

/**
 * 单个消息组件 - 用户消息
 */
export const UserMessageItem: React.FC<SingleMessageProps> = ({
    message,
    isHovered,
    isPinned,
    onCopy,
    onTogglePin
}) => {
    return (
        <UserMessage>
            <Typography sx={{ fontSize: '0.875rem' }}>{message.text}</Typography>
            <MessageActions
                className="message-actions"
                sx={{ opacity: isHovered ? 1 : 0 }}
            >
                <MessageActionButton
                    size="small"
                    onClick={onCopy ? onCopy : undefined}
                >
                    <CopyIcon fontSize="inherit" />
                </MessageActionButton>
                <MessageActionButton
                    size="small"
                    onClick={onTogglePin ? onTogglePin : undefined}
                >
                    {isPinned ?
                        <PushPinIcon fontSize="inherit" /> :
                        <PushPinOutlinedIcon fontSize="inherit" />
                    }
                </MessageActionButton>
            </MessageActions>
        </UserMessage>
    );
};

/**
 * 单个消息组件 - AI消息
 */
export const AIMessageItem: React.FC<SingleMessageProps> = ({
    message,
    isHovered,
    isPinned,
    onCopy,
    onTogglePin
}) => {
    const theme = useTheme();
    const isTyping = message.isTypingIndicator;

    return (
        <AIMessage className={message.isNew ? 'fade-in' : ''}>
            <Box sx={{ display: 'flex', alignItems: 'center', mb: 1 }}>
                <AIIcon>
                    <SmartToyIcon fontSize="small" style={{ fontSize: '0.9rem' }} />
                </AIIcon>
                <Typography variant="subtitle2" sx={{ fontWeight: 500 }}>AI</Typography>
            </Box>

            {/* 使用MarkdownRenderer渲染内容，并添加字号样式 */}
            <Box sx={{ fontSize: '0.875rem' }}>
                {isTyping ? (
                    <>
                        <MarkdownRenderer text={message.text || ''} />
                        <Box sx={{ mt: 1, display: 'inline-block' }}>
                            <TypingDots>
                                <span className="dot"></span>
                                <span className="dot"></span>
                                <span className="dot"></span>
                            </TypingDots>
                        </Box>
                    </>
                ) : (
                    <MarkdownRenderer text={message.text || ''} />
                )}
            </Box>
            
            <MessageActions
                className="message-actions"
                sx={{ opacity: isHovered ? 1 : 0 }}
            >
                <MessageActionButton
                    size="small"
                    onClick={onCopy ? onCopy : undefined}
                >
                    <CopyIcon fontSize="inherit" />
                </MessageActionButton>
                <MessageActionButton
                    size="small"
                    onClick={onTogglePin ? onTogglePin : undefined}
                >
                    {isPinned ?
                        <PushPinIcon fontSize="inherit" /> :
                        <PushPinOutlinedIcon fontSize="inherit" />
                    }
                </MessageActionButton>
            </MessageActions>
        </AIMessage>
    );
};

interface MessageItemProps {
    message: Message;
    onCopy?: (messageId: string) => void;
    onTogglePin?: (messageId: string) => void;
    pinnedMessageIds: Set<string>;
    selectedTextInfo?: import('../../../types/text.ts').SelectedTextInfo | null;
}

/**
 * 消息项组件 - 根据消息类型显示不同样式
 */
export const MessageItem: React.FC<MessageItemProps> = ({
    message,
    onCopy,
    onTogglePin,
    pinnedMessageIds,
    selectedTextInfo = null
}) => {
    const theme = useTheme();
    const { replaceSelectedText } = useNovel();
    const [isHovered, setIsHovered] = useState(false);
    const isPinned = pinnedMessageIds.has(message.id);
    const [isExpanded, setIsExpanded] = useState(true);
    const [showActions, setShowActions] = useState(false);
    const textContainerRef = useRef<HTMLDivElement>(null);
    const [isExceedsMaxHeight, setIsExceedsMaxHeight] = useState(false);
    const [showDiff, setShowDiff] = useState(false);
    const [isReplacing, setIsReplacing] = useState(false);

    // 从AI回复中提取润色后的内容
    const parseResult = useMemo(() => {
        if (!message.isUser && message.text && selectedTextInfo) {
            return extractPolishedText(message.text);
        }
        return null;
    }, [message.isUser, message.text, selectedTextInfo]);

    // 计算差异结果
    const diffResult = useMemo(() => {
        if (parseResult && selectedTextInfo && parseResult.polishedText) {
            return calculateTextDiff(selectedTextInfo.text, parseResult.polishedText);
        }
        return null;
    }, [parseResult, selectedTextInfo]);

    // 当有有效的润色结果时，自动显示差异对比
    useEffect(() => {
        if (parseResult && diffResult && (parseResult.hasExpectedFormat || parseResult.hasNonStandardFormat)) {
            setShowDiff(true);
        } else {
            setShowDiff(false);
        }
    }, [parseResult, diffResult]);

    // 编辑器服务替换备选方案 - 移到useCallback外部
    const fallbackToEditorService = useCallback((originalText: string, newText: string, diffStats: { addedChars: number, removedChars: number }) => {
        try {
            // 使用全局替换服务作为备选
            requestTextReplace({
                originalText,
                newText,
                options: {
                    formatAsHtml: false,
                    preserveFormatting: true
                }
            });
            
            // 显示成功提示
            showToast(`文本润色替换成功，添加了${diffStats.addedChars}个字符，删除了${diffStats.removedChars}个字符`);
            
            // 替换完成后清理
            setTimeout(() => {
                setIsReplacing(false);
                setShowDiff(false);
            }, 500);
            
            console.log('编辑器服务替换请求已发送');
        } catch (error) {
            console.error('替换文本失败', error);
            showErrorToast('替换文本失败，请重试');
            setIsReplacing(false);
        }
    }, []);

    // 执行替换
    const executeReplace = useCallback(() => {
        // 先进行严格的类型检查
        if (!selectedTextInfo || !parseResult || !diffResult) {
            console.error('执行替换前检查失败: 缺少必要数据', {
                hasSelectedTextInfo: !!selectedTextInfo,
                hasParseResult: !!parseResult,
                hasDiffResult: !!diffResult
            });
            return;
        }

        console.log('执行替换', {
            sourceId: selectedTextInfo.sourceId,
            startPosition: selectedTextInfo.startPosition,
            endPosition: selectedTextInfo.endPosition
        });

        // 设置替换中状态
        setIsReplacing(true);
        
        // 在类型保护后创建替换操作对象
        const replaceOperation: ReplaceOperation = {
            originalText: selectedTextInfo.text,
            newText: parseResult.polishedText,
            selectionInfo: selectedTextInfo,
            diffResult
        };
        
        // 获取需要的统计信息 - 在作用域外定义，以便在catch块中使用
        const diffStats = {
            addedChars: diffResult.statistics.addedChars,
            removedChars: diffResult.statistics.removedChars
        };
        
        try {
            // 首先尝试使用NovelContext中的高级替换功能
            replaceSelectedText(replaceOperation)
                .then(success => {
                    if (success) {
                        // 显示成功提示
                        showToast(`文本润色替换成功，添加了${diffStats.addedChars}个字符，删除了${diffStats.removedChars}个字符`);
                        
                        // 替换完成后清理
                        setTimeout(() => {
                            setIsReplacing(false);
                            setShowDiff(false);
                        }, 500);
                        
                        console.log('上下文替换请求已完成');
                    } else {
                        // 如果上下文替换失败，回退到使用编辑器服务
                        console.log('上下文替换失败，尝试使用编辑器服务替换');
                        fallbackToEditorService(selectedTextInfo.text, parseResult.polishedText, diffStats);
                    }
                })
                .catch(error => {
                    console.error('上下文替换出错:', error);
                    fallbackToEditorService(selectedTextInfo.text, parseResult.polishedText, diffStats);
                });
        } catch (error) {
            console.error('执行替换时出错:', error);
            fallbackToEditorService(selectedTextInfo.text, parseResult.polishedText, diffStats);
        }
    }, [parseResult, selectedTextInfo, diffResult, replaceSelectedText, fallbackToEditorService]);

    // 渲染差异展示组件
    const renderDiffDisplay = () => {
        if (!showDiff || !diffResult) return null;
        
        return (
            <Suspense fallback={<Box sx={{ display: 'flex', justifyContent: 'center', p: 2 }}><CircularProgress size={24} /></Box>}>
                <TextDiffDisplay 
                    diffResult={diffResult}
                    onReplace={executeReplace}
                    isReplaceEnabled={!isReplacing}
                />
            </Suspense>
        );
    };

    return (
        <MessageContainer
            onMouseEnter={() => setIsHovered(true)}
            onMouseLeave={() => setIsHovered(false)}
        >
            {message.isUser ? (
                <UserMessageItem
                    message={message}
                    isHovered={isHovered}
                    isPinned={isPinned}
                    onCopy={onCopy && (() => onCopy(message.id))}
                    onTogglePin={onTogglePin && (() => onTogglePin(message.id))}
                />
            ) : (
                <AIMessageItem
                    message={message}
                    isHovered={isHovered}
                    isPinned={isPinned}
                    onCopy={onCopy && (() => onCopy(message.id))}
                    onTogglePin={onTogglePin && (() => onTogglePin(message.id))}
                />
            )}
            {renderDiffDisplay()}
        </MessageContainer>
    );
}; 